package com.jxtc.enterprise.employee.controller;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jxtc.enterprise.common.config.MealImageURLConfig;
import com.jxtc.enterprise.common.constants.MealTypeEnum;
import com.jxtc.enterprise.common.constants.UserConstants;
import com.jxtc.enterprise.common.entity.Company;
import com.jxtc.enterprise.common.entity.Department;
import com.jxtc.enterprise.common.entity.MealConfig;
import com.jxtc.enterprise.common.entity.User;
import com.jxtc.enterprise.common.enums.ShowVipUserFoodEnum;
import com.jxtc.enterprise.common.mapper.CompanyMapper;
import com.jxtc.enterprise.common.mapper.DepartmentMapper;
import com.jxtc.enterprise.common.mapper.UserMapper;
import com.jxtc.enterprise.common.utils.*;
import com.jxtc.enterprise.common.vo.MiniAppSessoinVO;
import com.jxtc.enterprise.employee.vo.UserMealVO;
import com.jxtc.enterprise.employee.vo.WxLoginFailedVO;
import com.jxtc.enterprise.employee.vo.WxLoginSuccessVO;
import com.jxtc.enterprise.employee.vo.WxUserIndexPageInfoVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 用户小程序 首页 相关的接口
 */
@RestController
@RequestMapping("/employee/indexPage")
@RequiredArgsConstructor
@Slf4j
public class IndexPageController {

    private final UserMapper userMapper;
    private final MealImageURLConfig mealImageURLConfig;

    @Autowired
    private CompanyMapper companyMapper;

    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private JxCryptUtil jxCryptUtil;

    @Value("${createOrder.canOrderAllTime}")
    private String canOrderAllTimePhoneListStr;

    /**
     * 登录时，使用用户的微信号登录小程序，并且选择让用户授权获取用户手机号
     *
     * @param codeForOpenId      小程序代码在微信手机端，调用微信客户端内核方法，获取微信用户授权码，通过授权码获取消费者的微信openId
     * @param codeForPhoneNumber 小程序代码在微信手机端，调用微信客户端内核方法，获取微信用户授权获取手机号的授权码，通过此授权码，可以调用微信平台api，获取到用户微信绑定的手机号
     * @return
     */
    @ApiResponse(responseCode = "200", description = "用户登录使用的手机号已经被公司HR录入时，返回200，并返回用户所属公司信息",
            content = @Content(schema = @Schema(example = UserConstants.loginSuccessApiResponseExample)))
    @ApiResponse(responseCode = "200", description = "用户登录使用的手机号未被公司HR录入时，返回401，并返回提示文本和售后客户二维码链接",
            content = @Content(schema = @Schema(example = UserConstants.loginFailedApiResponseExample)))
    @Parameter(name = "wxAuthorizeCode", description = "微信授权码")
    @Operation(summary = "1.1 登录", tags = {"1. 用户小程序-首页"})
    @GetMapping(value = "/loginWx", produces = {MediaType.APPLICATION_JSON_VALUE})
    Result<?> loginWx(String codeForOpenId, String codeForPhoneNumber) {

        String requestId = UUID.randomUUID().toString();
        log.info("requestId: {}, /loginWx, request params, codeForOpenId: {}, codeForPhoneNumber: {}",
                requestId, codeForOpenId, codeForPhoneNumber);
        String phoneNumber = getPhoneNumberByWxAuthorizeCode(codeForPhoneNumber);
        // 当无法从微信平台获取到用户手机号时，无法通过手机号查询该用户是否被hr录入，属于哪个公司，此时需要用户通过手机号和密码进行登录
        if (StringUtils.isEmpty(phoneNumber)) {
            Result<String> result = new Result<>();
            result.setCode(ResultCode.UNAUTHORIZED);
            result.setMessage("未知用户");
            result.setData(UserConstants.loginFailedApiResponseExample);
            log.info("requestId: {}, response body:{}", requestId, JSONObject.toJSONString(result));
            return result;
        }

        MiniAppSessoinVO miniAppSessoinEntity = code2Session(codeForOpenId);
        if (miniAppSessoinEntity == null || StringUtils.isEmpty(miniAppSessoinEntity.getOpenId())) {
            log.error("requestId: {}, 获取用户openId失败: {}", requestId, miniAppSessoinEntity);
            return Result.error("获取用户openId失败，请联系工作人员进行处理");
        }
        String openId = miniAppSessoinEntity.getOpenId();
        // 登录成功后，将用户的openId 更新到 user表中，微信支付时会使用到
        userMapper.update(new LambdaUpdateWrapper<User>()
                .eq(User::getPhoneNumber, phoneNumber)
                .set(User::getOpenId, openId)
                // update(Wrapper<T> updateWrapper) 方法，不会自动为 update_time 赋值，需要手动赋值
                .set(User::getUpdateTime, LocalDateTime.now()));

        String token = JwtUtil.sign(phoneNumber, JwtUtil.JX_USER_LOGIN_PASSWORD);
        WxLoginSuccessVO loginSuccessVO = buildWxMinAppLoginSuccessInfo(phoneNumber, token);
        if (loginSuccessVO == null) {
            log.error("requestId: {}, 用户手机号: {} 在系统中未录入", requestId, phoneNumber);
            Result<WxLoginSuccessVO> result = new Result<>();
            result.setCode(ResultCode.UNAUTHORIZED);
            result.setMessage("用户手机号 " + phoneNumber + " 在系统中未录入");
            result.setData(null);

            return result;
        }

        Result<WxLoginSuccessVO> result = new Result<>();
        result.setCode(ResultCode.SUCCESS);
        result.setMessage("success");
        result.setData(loginSuccessVO);

        log.info("requestId: {}, response body:{}", requestId, JSONObject.toJSONString(result));
        return result;
    }

    /**
     * 登录时，使用用户的微信号登录小程序，并且选择让用户授权获取用户手机号
     *
     * @param phone
     * @param password
     * @param codeForOpenId 小程序代码在微信手机端，调用微信客户端内核方法，获取微信用户授权码，通过授权码获取消费者的微信openId
     * @return
     */
    @ApiResponse(responseCode = "200", description = "当用户无法通过微信授权登录时，用户使用手机号和密码进行登录，返回200，并返回用户所属公司信息",
            content = @Content(schema = @Schema(examples = {UserConstants.loginSuccessApiResponseExample, UserConstants.loginForbiddenApiResponseExample})))
    @Parameters({@Parameter(name = "phone", description = "手机号"), @Parameter(name = "password", description = "密码"),
            @Parameter(name = "codeForOpenId", description = "用于获取openid的授权码")})
    @Operation(summary = "1.2 手机号+密码 登录", tags = {"1. 用户小程序-首页"})
    @GetMapping("/loginUserPassword")
    Result<?> loginUserPassword(String phone, String password, String codeForOpenId) {

        String requestId = UUID.randomUUID().toString();
        log.info("requestId:{}, /loginUserPassword 使用手机号和密码登录，phone: {}, codeForOpenId: {}",
                requestId, phone, codeForOpenId);

        User userInfo = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhoneNumber, phone).eq(User::getDelFlag, 0));
        if (userInfo != null && Objects.equals(password, userInfo.getPasswd())) {
            MiniAppSessoinVO miniAppSessoinEntity = code2Session(codeForOpenId);
            if (miniAppSessoinEntity == null || StringUtils.isEmpty(miniAppSessoinEntity.getOpenId())) {
                log.error("requestId:{},获取用户openId失败: {}", requestId, miniAppSessoinEntity);
                return Result.error("获取用户openId失败，请联系工作人员进行处理");
            }
            String openId = miniAppSessoinEntity.getOpenId();
            // 登录成功后，将用户的openId 更新到 user表中，微信支付时会使用到
            userMapper.update(new LambdaUpdateWrapper<User>()
                    .eq(User::getPhoneNumber, phone).set(User::getOpenId, openId));
            String token = JwtUtil.sign(phone, JwtUtil.JX_USER_LOGIN_PASSWORD);
            WxLoginSuccessVO loginSuccessVO = buildWxMinAppLoginSuccessInfo(phone, token);
            Result<WxLoginSuccessVO> result = new Result<>();
            result.setCode(ResultCode.SUCCESS);
            result.setMessage("success");
            result.setData(loginSuccessVO);
            log.warn("requestId: {},response: {}", requestId, loginSuccessVO);
            return result;
        }

        Result<WxLoginFailedVO> result = new Result<>();
        result.setCode(ResultCode.FORBIDDEN);
        result.setMessage("账号未录入或密码错误");
        WxLoginFailedVO loginFailedVO = new WxLoginFailedVO();
        loginFailedVO.setMessage("账号或密码错误，请联系公式HR或扫描下方二维码联系平台管理员");
        loginFailedVO.setQrcodeImageUrl("https://oss.yun.huawei.com/qrcode/qrcode.png");
        result.setData(loginFailedVO);

        return result;
    }

    @ApiResponse(responseCode = "200", description = "用户登出", content = {@Content(schema = @Schema(example = UserConstants.logoutApiResponseExample))})
    @Parameter(name = "userId", description = "用户id")
    @Operation(summary = "1.3 登出", tags = {"1. 用户小程序-首页"})
    @GetMapping("/logout")
    Result<?> logout(String userId) {

        String requestId = UUID.randomUUID().toString();
        log.info("requestId:{}, /logout 退出登录，userId: {}", requestId, userId);
        // todo 将用户之前登录时的token 从redis中删除
        Result<String> result = new Result<>();
        result.setCode(ResultCode.SUCCESS);
        result.setMessage("success");
        result.setData("登出成功");

        return result;
    }


    @ApiResponse(responseCode = "200", description = "当用户通过微信授权登录或手机号+密码登录成功后，进入首页时，获取首页用户信息和用所属公司信息",
            content = {@Content(schema = @Schema(example = UserConstants.userInfoAndCompanyInfoApiResponseExample))})
    @Parameter(name = "phoneNumber", description = "用户绑定微信的手机号")
    @Operation(summary = "1.4 首页用户信息和用户所属公司信息", tags = {"1. 用户小程序-首页"})
    @GetMapping(value = "/queryUserInfoAndCompanyInfoByUserId")
    Result<WxUserIndexPageInfoVo> queryUserInfoAndCompanyInfoByUserId(String phoneNumber) {
        String requestId = UUID.randomUUID().toString();
        log.warn("requestId: {}, /queryUserInfoAndCompanyInfoByUserId, request params: {}", requestId, phoneNumber);
        Result<WxUserIndexPageInfoVo> result = new Result<>();
        result.setCode(ResultCode.SUCCESS);
        result.setMessage("success");

        // 复用已有的方法，不需要传递token，只需要从返回值中获取用户名，余额，公司图片等信息
        WxLoginSuccessVO userAndCompanyBasicInfo = buildWxMinAppLoginSuccessInfo(phoneNumber, null);
        WxUserIndexPageInfoVo userIndexPageInfoVo = getWxUserIndexPageInfoVo(userAndCompanyBasicInfo);
        result.setData(userIndexPageInfoVo);
        log.warn("requestId: {}, response: {}", requestId, userIndexPageInfoVo);
        return result;
    }

    /**
     * 复用已有的方法，不需要传递token，只需要从返回值中获取用户名，余额，公司图片等信息
     * 从 WxLoginSuccessVO 类型返回值中提取用户基本信息和公司基本信息
     *
     * @param userAndCompanyBasicInfo
     * @return
     */
    private WxUserIndexPageInfoVo getWxUserIndexPageInfoVo(WxLoginSuccessVO userAndCompanyBasicInfo) {
        WxUserIndexPageInfoVo userIndexPageInfoVo = new WxUserIndexPageInfoVo();

        userIndexPageInfoVo.setUserName(userAndCompanyBasicInfo.getUserName());
        userIndexPageInfoVo.setBalance(userAndCompanyBasicInfo.getBalance());
        userIndexPageInfoVo.setCompanyId(userAndCompanyBasicInfo.getCompanyId());
        userIndexPageInfoVo.setCompanyName(userAndCompanyBasicInfo.getCompanyName());
        userIndexPageInfoVo.setDepartId(userAndCompanyBasicInfo.getDepartId());
        userIndexPageInfoVo.setDepartName(userAndCompanyBasicInfo.getDepartName());
        userIndexPageInfoVo.setHeadImageUrl(userAndCompanyBasicInfo.getHeadImageUrl());
        userIndexPageInfoVo.setMiddleImageUrl(userAndCompanyBasicInfo.getMiddleRegionImageUrl());
        userIndexPageInfoVo.setNoteImagesUrl(userAndCompanyBasicInfo.getNoteImageUrl());
        userIndexPageInfoVo.setShowVipUserFoodBtn(userAndCompanyBasicInfo.getShowVipUserFoodBtn());
        return userIndexPageInfoVo;
    }

    private String getPhoneNumberByWxAuthorizeCode(String code) {

        //通过appid和secret来获取token
        // todo 将 appid和secret 加密保存在配置文件中，程序运行时再进行解密
        // String tokenUrl = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", "wx3b5031cdda30712f", "a1d70a342b9ed3efb2a1210607476dea");
        String tokenUrl = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", "wxcdff2287ac2c9afa", "7eec4ba25ea40c38e7b74ff4944211c3");
        JSONObject token = RestUtils.get(tokenUrl);

        //通过token和code来获取用户手机号
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + token.getString("access_token");

        //封装请求体
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("code", code);

        //封装请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(paramMap, headers);

        //通过RestTemplate发送请求，获取到用户手机号码
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<Object> response = restTemplate.postForEntity(url, httpEntity, Object.class);

        log.warn("getPhoneNumber response body: {}", response.getBody());
        Map responseBody = (Map) response.getBody();
        Integer errCode = (Integer) responseBody.get("errcode");
        String phoneNumber = "";
        if (errCode.intValue() == 0) {
            phoneNumber = (String) ((Map) responseBody.get("phone_info")).get("purePhoneNumber");
        } else {
            log.error("通过微信授权码获取用户手机号失败, 错误提示： {}", response.getBody());
        }

        return phoneNumber;
    }

    /**
     * 微信授权登录或手机号+密码登录成功后， 根据用户手机号，查询用户表和 用户所属公司信息表，获取用户基本信息和公司信息
     *
     * @param phone
     * @param token
     * @return
     */
    private WxLoginSuccessVO buildWxMinAppLoginSuccessInfo(String phone, String token) {

        WxLoginSuccessVO loginSuccessVO = new WxLoginSuccessVO();
        // 查询company表，获取未某个公司配置的 点餐小程序 首页背景图，底部通知轮播图
        List<HashMap<String, Object>> list = userMapper.queryUserBasicInfoAndCompanyBasicInfo(phone);
        if (CollectionUtils.isEmpty(list)) {
            log.error("手机号 {} 在系统中查不到", phone);
            return null;
        }
        // 当同一个公司有多个手机号相同的员工时，查询sql时按照员工记录的 update_date 降序排列，此处取第一个，
        // 当对某个用户 编辑后保存操作（可不做任何操作，仅调用编辑接口即可）后，用户的update_time会更新，就会成为查询结果中的第一个
        HashMap<String, Object> resultSet = list.get(0);
        // 员工所属公司id
        String companyId = (String) resultSet.get("companyId");
        loginSuccessVO.setCompanyId(companyId);
        // 员工所属部门id
        String departId = (String) resultSet.get("departId");
        loginSuccessVO.setDepartId(departId);
        // 员工使用的菜单id
        String menuId = (String) resultSet.get("menuId");
        loginSuccessVO.setMenuId(menuId);
        // 用小程序首页为各个公司提供展示公司信息，公司通知轮播图区域，允许各个公司定制 图片展示和通知信息
        String images = (String) resultSet.getOrDefault("images", "");
        JSONObject jsonObject = JSONObject.parseObject(images);
        String headImage = jsonObject.getString("headImage");
        loginSuccessVO.setHeadImageUrl(headImage);
        String middleImage = jsonObject.getString("middleImage");
        loginSuccessVO.setMiddleRegionImageUrl(middleImage);
        List<String> noteImages = jsonObject.getJSONArray("noteImages").toJavaList(String.class);
        loginSuccessVO.setNoteImageUrl(noteImages);
        // 用户名称或昵称
        String userName = (String) resultSet.get("username");
        loginSuccessVO.setUserName(userName);
        // 用户余额，db中存放的数据单位为分，类型为整数；返回给前端显示的时候需要转换成元
        Integer balance = (Integer) resultSet.get("balance");
        loginSuccessVO.setBalance(1.0f * balance / 100);
        // 用户手机号
        loginSuccessVO.setPhoneNumber(phone);
        loginSuccessVO.setToken(token);

        // 是否显示客户餐按钮，1 显示客户餐，2 不显示客户餐
        Integer showVipFoodBtn = (Integer) resultSet.get("showVipFoodBtn");
        boolean showVipUserFoodBtn = Objects.equals(showVipFoodBtn, ShowVipUserFoodEnum.SHOW_VIP_USER_FOOD.getValue());
        loginSuccessVO.setShowVipUserFoodBtn(showVipUserFoodBtn);

        Company company = companyMapper.selectOne(
                new LambdaQueryWrapper<Company>().eq(Company::getDelFlag, false).eq(Company::getId, companyId));
        loginSuccessVO.setCompanyName(company.getName());
        Department department = departmentMapper.selectOne(
                new LambdaQueryWrapper<Department>().eq(Department::getDelFlag, false).eq(Department::getId, departId));
        loginSuccessVO.setDepartName(department.getName());

        if (StringUtils.isNoneBlank(canOrderAllTimePhoneListStr) && canOrderAllTimePhoneListStr.contains(phone)) {
            log.warn("in_login_check_user_can_order_all_time canOrderAllTimePhoneListStr: {}, user phone: {}, canOrderAllTime: true", canOrderAllTimePhoneListStr, phone);
            loginSuccessVO.setCanOrderAllTime(true);
        }

        return loginSuccessVO;
    }

    /**
     * 根据用户临时授权code，获取openid 和 session_key （微信接口返回的数据都是加密的，需要使用此 session_key 进行解密）
     *
     * @param code
     * @return
     */
    private MiniAppSessoinVO code2Session(String code) {
        // todo 将 appid和secret 加密保存在配置文件中，程序运行时再进行解密
        // String url = "https://api.weixin.qq.com/sns/jscode2session?appid=wx3b5031cdda30712f&secret=a1d70a342b9ed3efb2a1210607476dea&js_code=" + code + "&grant_type=authorization_code";
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=wxcdff2287ac2c9afa&secret=7eec4ba25ea40c38e7b74ff4944211c3&js_code=" + code + "&grant_type=authorization_code";
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);

        if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) {
            String sessionData = responseEntity.getBody();
            MiniAppSessoinVO sessoinEntity = JSONObject.parseObject(sessionData, MiniAppSessoinVO.class);
            return sessoinEntity;
        } else {
            return null;
        }
    }

    @ApiResponse(responseCode = "200", description = "code 为 200 时，data 字段为该员工可以点餐类型的列表")
    @Parameter(name = "phone", description = "用户手机号（可选）")
    @Parameter(name = "companyId", description = "用户所属公司 ID（可选）")
    @Operation(summary = "1.5 获取该员工可以点餐的时段", tags = {"1. 用户小程序-首页"}, operationId = "1.5")
    @GetMapping("/queryUserMeals")
    public Result<List<UserMealVO>> queryUserMeals(@RequestParam(required = false) String companyId, @RequestParam(required = false) String phone) {
        String requestId = UUID.randomUUID().toString();
        log.info("requestId:{}, /queryUserMeals, companyId: {}, phone: {}", requestId, companyId, phone);

        List<UserMealVO> userMealVOList = buildDefaultMealTypeList();

        // 只有当登录后接口入参才会传递 公司id，且公司id不为空，才根据公司实际配置，修改6个用餐时段的enable值；
        // 如果未登录 则不执行该if分支逻辑，直接将 6个enable为false的数据项返回给前端
        if (companyId != null && !companyId.isEmpty()) {
            Company company = companyMapper.selectById(companyId);
            if (company == null) {
                throw new IllegalArgumentException("ID 为 " + companyId + " 的公司不存在，请联系管理员排查");
            }

            String mealsConfig = company.getMealsConfig();
            List<MealConfig> mealConfigList = JSONObject.parseArray(mealsConfig, MealConfig.class);

            // 根据该公司配置的供餐时间段（meals_config），确定哪些餐品类型是可以点击的
            for (MealConfig mealConfig : mealConfigList) {
                // 如果该公司启用了当前用餐时段，将 userMealVOList 中对应用餐时段的 enabled 字段设置为 true
                if (mealConfig.getEnabled()) {
                    for (UserMealVO mealVO : userMealVOList) {
                        if (mealVO.getMealTypeEn().equals(mealConfig.getMealType())) {
                            mealVO.setEnabled(true);
                        }
                    }
                }
            }
        }

        log.info("requestId:{}, /queryUserMeals, result: {}", requestId, JSONObject.toJSONString(userMealVOList));
        return ResultGenerator.genSuccessResult(userMealVOList);
    }

    /**
     * 构建默认的餐品类型列表，用户未登录时可以直接返回默认用餐类型列表
     */
    private List<UserMealVO> buildDefaultMealTypeList() {
        List<UserMealVO> userMealVOList = new ArrayList<>();

        for (MealTypeEnum mealTypeEnum : MealTypeEnum.values()) {
            UserMealVO userMealVO = new UserMealVO(mealTypeEnum.getMealTypeCn(), mealTypeEnum.getMealTypeEn(), "https://xxxx", false);

            // 设置不同的用餐类型的图片链接
            if (MealTypeEnum.BREAK_FAST.getCode() == mealTypeEnum.getCode()) {
                userMealVO.setImageUrl(mealImageURLConfig.getBreakfast());
            }

            if (MealTypeEnum.LUNCH.getCode() == mealTypeEnum.getCode()) {
                userMealVO.setImageUrl(mealImageURLConfig.getLunch());
            }

            if (MealTypeEnum.DINNER.getCode() == mealTypeEnum.getCode()) {
                userMealVO.setImageUrl(mealImageURLConfig.getDinner());
            }

            if (MealTypeEnum.MORNING_TEA.getCode() == mealTypeEnum.getCode()) {
                userMealVO.setImageUrl(mealImageURLConfig.getMorningTea());
            }

            if (MealTypeEnum.AFTERNOON_TEA.getCode() == mealTypeEnum.getCode()) {
                userMealVO.setImageUrl(mealImageURLConfig.getAfternoonTea());
            }

            if (MealTypeEnum.NIGHT_SNACK.getCode() == mealTypeEnum.getCode()) {
                userMealVO.setImageUrl(mealImageURLConfig.getNightSnack());
            }

            userMealVOList.add(userMealVO);
        }

        return userMealVOList;
    }

    /**
     * 有小程序调用，触发更新用户的openId，用于作为支付时的参数
     *
     * @param phone
     * @param authorizeCode
     */
    @GetMapping(value = "/requestRefreshOpenIdByAuthorizeCode")
    public void requestRefreshOpenIdByAuthorizeCode(String phone, String authorizeCode) {

        String requestId = UUID.randomUUID().toString();
        log.info("requestId:{}, /requestRefreshOpenIdByAuthorizeCode 更新用户openId，phone: {}, authorizeCode: {}",
                requestId, phone, authorizeCode);

        if (StringUtils.isNotEmpty(authorizeCode)) {
            log.info("requestId:{}, 更新用户openId，用户: {}, 小程序端调用接口传递了授权码: {}",
                    requestId, phone, authorizeCode);

            // 调用微信接口，以授权码为入参，获取用户微信的openId，用于创建预支付订单
            MiniAppSessoinVO miniAppSessionEntity = WxUtils.code2Session(authorizeCode);
            if (miniAppSessionEntity == null || StringUtils.isEmpty(miniAppSessionEntity.getOpenId())) {
                log.error("requestId:{}, 更新用户openId，获取用户openId失败: {}", requestId, miniAppSessionEntity);
            } else {
                String openId = miniAppSessionEntity.getOpenId();
                int count = userMapper.update(
                        new LambdaUpdateWrapper<User>()
                                .eq(User::getPhoneNumber, phone)
                                .set(User::getOpenId, openId)
                                // update(Wrapper<T> updateWrapper) 方法，不会自动为 update_time 赋值，需要手动赋值
                                .set(User::getUpdateTime, LocalDateTime.now()));
                log.info("requestId:{}, 更新用户openId，获取用户openId成功,用户:{}, 最新openId:{}, 更新user表中缓存的openId，更新结果: {}",
                        requestId, phone, openId, count);
            }
        } else {
            log.error("requestId:{}, 接口入参错误，授权码为空, phone:{}, authorizeCode: {}",
                    requestId, phone, authorizeCode);
        }
    }
}
